import FCMatrix, FCVector
import random
from maya import OpenMaya as om
from maya import cmds


def interpolate( _Alpha, _X0, _X1 ):
    return _X0 + ( (_X1 - _X0) * _Alpha )
    
def clamp( _X, _Min, _Max ):
    if _X < _Min: return _Min
    if _X > _Max: return _Max
    return _X
    
def remapInterval( _X, _In0, _In1, _Out0, _Out1 ):
    _Relative = (_X - _In0) / (_In1 - _In0)
    
    return interpolate( _Relative, _Out0, _Out1 )
    
def remapIntervalClamp( _X, _In0, _In1, _Out0, _Out1 ):
    _Relative = (_X - _In0) / (_In1 - _In0)
    
    return interpolate( clamp( _Relative, 0, 1 ), _Out0, _Out1 )
    
def intervalComparison( _X, _Lower, _Upper ):
    if _X < _Lower: return -1
    if _X > _Upper: return 1
    return 0
    
def scalarRandomWalk( _Initial, _WalkSpeed, _Min, _Max ):
    _Next = _Initial + ( ( ( random.uniform( 0, 1 ) * 2 ) - 1 ) * _WalkSpeed )
    if _Next < _Min: return _Min
    if _Next > _Max: return _Max
    return _Next

def square( _X ):
    return _X * _X
    
def blendIntoAccumulator( _SmoothRate, _NewValue, _SmoothedAccumulator ):
    return interpolate( clamp( _SmoothRate, 0, 1 ), _SmoothedAccumulator, _NewValue )
    
def isZeroVector( _Vector ):
    if _Vector.x == 0 and _Vector.y == 0 and _Vector.z == 0:
        return True
    else: return False
    
def parallelComponent( _Source, _UnitBasis ):
    _Projection = _Source * _UnitBasis
    return _UnitBasis * _Projection
    
def perpendicularComponent( _Source, _UnitBasis ):
    return _Source - parallelComponent( _Source, _UnitBasis )
    
def distance( _A, _B ):
    return (_A - _B).length()
    
def truncateLength( _Vector, _Length ):
    _MaxLengthSquared = _Length  * _Length
    _VecLengthSquared = _Vector.length() * _Vector.length()
    
    if _VecLengthSquared <= _MaxLengthSquared:
        return _Vector
    else:
        return _Vector.normal() * _Length
        
def randomVectorInUnitRadiusSphere():
    _Vector = om.MVector()
    _Vector.x = (uniform( 0, 1 ) * 2) - 1
    _Vector.y = (uniform( 0, 1 ) * 2) - 1
    _Vector.z = (uniform( 0, 1 ) * 2) - 1
        
    while _Vector.length() >= 1:
        _Vector.x = (uniform( 0, 1 ) * 2) - 1
        _Vector.y = (uniform( 0, 1 ) * 2) - 1
        _Vector.z = (uniform( 0, 1 ) * 2) - 1
        
    return _Vector
    
def randomUnitVector():
    return randomVectorInUnitRadiusSphere().normal()
    
def randomUnitVectorOnXZPlane():
    _Vector = randomVectorInUnitRadiusSphere()
    _Vector.y = 0
    return _Vector.normal()

def limitMaxDeviationAngleUtility( _InsideOrOutside, _Source, _CosOfConeAngle, _Basis ):
    _SourceLength = _Source.length()
    if 0 == _SourceLength: return _Source
    
    _Direction = _Source / _SourceLength
    _CosOfSourceAngle = _Direction * _Basis
    
    if _InsideOrOutside:
        if _CosOfSourceAngle >= _CosOfConeAngle: return _Source
    else:
        if _CosOfSourceAngle <= _CosOfConeAngle: return _Source
        
    _Perp = perpendicularComponent( _Source, _Basis )
    _UnitPerp = _Perp.normal()
    
    _PerpDist = square( 1- (_CosOfConeAngle * _CosOfConeAngle) )
    _C0 = _Basis * _CosOfConeAngle
    _C1 = _UnitPerp * _PerpDist
    return (_C0 + _C1) * _SourceLength
    
def limitMaxDeviationAngle( _Source, _CosOfConeAngle, _Basis ):
    return limitMaxDeviationAngleUtility( True, _Source, _CosOfConeAngle, _Basis )
    
########################################################################################    
def distance(a,b):    
    p1 = om.MPoint( cmds.xform( a, ws=1, t=1 ) )
    p2 = om.MPoint( cmds.xform( b, ws=1, t=1 ) )   
    return p1.distanceTo(p2)        


def pointTolocalspace(objpos, head, side, pos):
    transpoint = objpos
    matTransform = FCMatrix.matrix2D()
    tx = -pos.dot(head)
    ty = -pos.dot(side)
    matTransform._11 = head.x
    matTransform._12 = side.x
    matTransform._21 = head.y
    matTransform._22 = side.y
    matTransform._31 = tx
    matTransform._32 = ty
    result = matTransform.transformVector2D(transpoint)
    return result

def pointToworldspace(objpos,head,side,pos):
    transpoint = objpos
    matTransform = FCMatrix.matrix2D()
    matTransform.rotateex(head,side)
    matTransform.tranlate(pos.x,pos.y)
    result = matTransform.transformVector2D(transpoint)
    return result
    
def vectorToworldspace(vec,head,side):
    transvec = vec
    matTransform = FCMatrix.matrix2D()
    matTransform.rotateex(head,side)
    result = matTransform.transformVector2D(transvec)
    return result
    
def distSqPointLineSegment(A,B,C):
    R = (C - A).dot(B-A) / (B - A).lengthsq()
    if 0.0>R:
        return (C-A).lengthsq()
    elif 1.0<R:
        return (C-B).lengthsq()
    else:
        return (C-A+(R*(B-A))).lengthsq()

def determinant(vector1, vector2):
    return vector1.x * vector2.y - vector1.y * vector2.x

def leftof(A,B,C):
    return determinant(A-C, B-A)  
    
def LineIntersection2D(A,B,C,D,_dist,_point):
    rTop = (A.y-C.y)*(D.x-C.x)-(A.x-C.x)*(D.y-C.y)
    rBot = (B.x-A.x)*(D.y-C.y)-(B.y-A.y)*(D.x-C.x)
    sTop = (A.y-C.y)*(B.x-A.x)-(A.x-C.x)*(B.y-A.y)
    sBot = (B.x-A.x)*(D.y-C.y)-(B.y-A.y)*(D.x-C.x)
           
    if ((rBot == 0)or(sBot==0)):
        return False 

    r = rTop/rBot
    s = sTop/sBot

    if( (r > 0) and (r < 1) and (s > 0) and (s < 1) ):
        _dist[0] = FCVector.vec2DDistance(A,B)*r
        _point[0] = A+((B-A)*r)	    	    
        return True
    else:
        _dist[0] = 0
    return False
